package com.ruoyi.common.utils.robot;

import com.alibaba.fastjson.JSONObject;
import okhttp3.*;
import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Base64Utils;

import javax.net.ssl.HttpsURLConnection;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.util.Base64;
import java.util.List;
import java.util.concurrent.TimeUnit;

public class WeChatBotUtils {

    private Logger log = LoggerFactory.getLogger(this.getClass());

    // 配置的群机器人Webhook地址
    private String botUrl;
    // 配置代理服务器
    private String hostname;
    private int port;

    /**
     *	@content：要发送的消息
     *	botUrl：机器人的webhook
     */
    public String callWeChatBot(String content) {

        OkHttpClient client = new OkHttpClient()
                .newBuilder()
                .build();
        MediaType mediaType = MediaType.parse("application/json");
        RequestBody body = RequestBody.create(mediaType, content);
        Request request = new Request.Builder()
                .url(botUrl)
                .method("POST", body)
                .addHeader("Content-Type", "application/json")
                .build();
        Response response = null;
        try {
            response = client.newCall(request).execute();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return response.message();
    }
    // 需要使用代理时调用的构造函数
    public WeChatBotUtils(String botUrl, String hostname, int port) {
        this.botUrl = botUrl;
        this.hostname = hostname;
        this.port = port;
    }

    // 直接从配置中获取代理信息
    public WeChatBotUtils(String botUrl, boolean byProxy) {
        this.botUrl = botUrl;
        if (byProxy) {
            hostname = System.getProperty("proxyHost");
            port = Integer.valueOf(System.getProperty("proxyPort"));
        }
    }

    /**
     * 发送文字消息
     *
     * @param msg 需要发送的消息
     * @return
     * @throws Exception
     */
    public String sendTextMsg(String msg) throws Exception {
        JSONObject text = new JSONObject();
        text.put("content", msg);
        JSONObject reqBody = new JSONObject();
        reqBody.put("msgtype", "text");
        reqBody.put("text", text);
        reqBody.put("safe", 0);

        return callWeChatBot(reqBody.toString());
    }

    /**
     * 发送图片消息，需要对图片进行base64编码并计算图片的md5值
     *
     * @param path 需要发送的图片路径
     * @return
     * @throws Exception
     */
    public String sendImgMsg(String path) throws Exception {

        String base64 = "";
        String md5 = "";

        // 获取Base64编码
        try {
            FileInputStream inputStream = new FileInputStream(path);
            byte[] bs = new byte[inputStream.available()];
            inputStream.read(bs);
            base64 = Base64.getEncoder().encodeToString(bs);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 获取md5值
        try {
            FileInputStream inputStream = new FileInputStream(path);
            byte[] buf = new byte[inputStream.available()];
            inputStream.read(buf);
            md5 = DigestUtils.md5Hex(buf);
        } catch (IOException e) {
            e.printStackTrace();
        }

        JSONObject image = new JSONObject();
        image.put("base64", base64);
        image.put("md5", md5);
        JSONObject reqBody = new JSONObject();
        reqBody.put("msgtype", "image");
        reqBody.put("image", image);
        reqBody.put("safe", 0);

        return callWeChatBot(reqBody.toString());
    }

    /**
     * 发送图片消息，需要对图片进行base64编码并计算图片的md5值
     *
     * @param imgUrl 需要发送的图片url
     * @return
     * @throws Exception
     */
    public String sendImgUrl(String imgUrl) throws Exception {

        String base64 = "";
        String md5 = "";

        URL url = null;
        InputStream is = null;
        ByteArrayOutputStream outStream = null;
        HttpURLConnection httpUrl = null;

        try {
            url = new URL(imgUrl);
            httpUrl = (HttpURLConnection) url.openConnection();
            httpUrl.connect();
            httpUrl.getInputStream();

            is = httpUrl.getInputStream();
            outStream = new ByteArrayOutputStream();

            //创建一个Buffer字符串
            byte[] buffer = new byte[1024];
            //每次读取的字符串长度，如果为-1，代表全部读取完毕
            int len = 0;
            //使用输入流从buffer里把数据读取出来
            while( (len = is.read(buffer)) != -1 ){
                //用输出流往buffer里写入数据，中间参数代表从哪个位置开始读，len代表读取的长度
                outStream.write(buffer, 0, len);
            }

            base64 = Base64Utils.encodeToString(outStream.toByteArray());

        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally {
            is.close();
            outStream.close();
        }

        // 获取md5值
        try {
            url = new URL(imgUrl);
            httpUrl = (HttpsURLConnection) url.openConnection();
            httpUrl.connect();
            httpUrl.getInputStream();

            is = httpUrl.getInputStream();
            md5 = DigestUtils.md5Hex(is);

        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            is.close();
            outStream.close();
        }

        JSONObject image = new JSONObject();
        image.put("base64", base64);
        image.put("md5", md5);
        JSONObject reqBody = new JSONObject();
        reqBody.put("msgtype", "image");
        reqBody.put("image", image);
        reqBody.put("safe", 0);

        return callWeChatBot(reqBody.toString());
    }

    /**
     * 发送MarKDown消息
     *
     * @param msg 需要发送的消息
     * @return
     * @throws Exception
     */
    public String sendMarKDownMsg(String msg) throws Exception {
        JSONObject markdown = new JSONObject();
        markdown.put("content", msg);
        JSONObject reqBody = new JSONObject();
        reqBody.put("msgtype", "markdown");
        reqBody.put("markdown", markdown);
        reqBody.put("safe", 0);

        return callWeChatBot(reqBody.toString());
    }

    /**
     * 发送News消息
     *
     * @param msg 需要发送的消息
     * @return
     * @throws Exception
     */
    public String sendNewsMsg(List<JSONObject> msg) throws Exception {
        JSONObject news = new JSONObject();
        news.put("articles",msg);
        JSONObject reqBody = new JSONObject();
        reqBody.put("msgtype", "news");
        reqBody.put("news", news);
        reqBody.put("safe", 0);
        return callWeChatBot(reqBody.toString());
    }

    /**
     * 发送文件消息，需要先将文件上传到企业微信临时素材，再根据获取的media_id调用群机器人
     *
     * @param path 需要发送的文件路径
     * @return
     * @throws Exception
     */
    public String sendFileMsg(String path) throws Exception {
        File file = new File(path);

        // 构造RequestBody对象，用来携带要提交的数据；需要指定MediaType，用于描述请求/响应 body 的内容类型
        MediaType contentType = MediaType.parse("application/form-data; boundary");
        RequestBody body = RequestBody.create(contentType, file);
        RequestBody requestBody = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("file", file.getName(), body)
                .build();

        // 上传到临时素材
        String key = botUrl.substring(botUrl.indexOf("key="));
        System.out.println(key);
        String mediaUrl = "https://qyapi.weixin.qq.com/cgi-bin/webhook/upload_media?type=file&"+key;
        log.info("将文件" + path+ "上传到临时素材：" + mediaUrl);
        String respMsg = okHttp(requestBody, mediaUrl);

        // 获取临时素材id
        JSONObject result = JSONObject.parseObject(respMsg);
        String media_id = result.getString("media_id");

        JSONObject fileJson = new JSONObject();
        fileJson.put("media_id", media_id);
        JSONObject reqBody = new JSONObject();
        reqBody.put("msgtype", "file");
        reqBody.put("file", fileJson);
        reqBody.put("safe", 0);

        // 调用群机器人发送消息
        return callWeChatBot(reqBody.toString());
    }

    /**
     *
     * @param body 携带需要提交的数据
     * @param url 请求地址
     * @return
     * @throws Exception
     */
    public String okHttp(RequestBody body, String url) throws Exception {
        // 构造和配置OkHttpClient
        OkHttpClient client;
        if(hostname != null && port != 0){
            client = new OkHttpClient.Builder()
                    .proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(hostname, port))) // 内网使用代理，不需要可注释
                    .connectTimeout(10, TimeUnit.SECONDS) // 设置连接超时时间
                    .readTimeout(20, TimeUnit.SECONDS) // 设置读取超时时间
                    .build();
        } else{
            client = new OkHttpClient.Builder()
                    .connectTimeout(10, TimeUnit.SECONDS) // 设置连接超时时间
                    .readTimeout(20, TimeUnit.SECONDS) // 设置读取超时时间
                    .build();
        }

        // 构造Request对象
        Request request = new Request.Builder()
                .url(url)
                .post(body)
                .addHeader("cache-control", "no-cache") // 响应消息不缓存
                .build();

        // 构建Call对象，通过Call对象的execute()方法提交异步请求
        Response response = null;
        try {
            response = client.newCall(request).execute();
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 请求结果处理
        byte[] datas = response.body().bytes();
        String respMsg = new String(datas);
        log.info("返回结果：" + respMsg);

        return respMsg;
    }

}
